/*
This file contains the header information corresponding to the Graph class.
The Graph class contains the data structure and the algorithms related to
known i.i.d. with integral types input model. See comments below.

Copyright (C) 2018  Denis Pankratov

Modifications Copyright (C) 2019 Christodoulos Karavasilis

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

#pragma once
#include <vector>
#include <map>
#include <algorithm>
#include <string>
#include <iostream>
#include <queue>
#include "assert.h"
#include <random>
#include "glpk.h" // for Brubach
#include <cmath>
#include <stack>
#include "bmcommon.h"
using namespace std;



/*
Undirected graph in the adjacency format representation.
adj -- adjacency lists representation
adj.size() -- number of nodes in the graph
Each node is an integer between 0 and adj.size()-1 (inclusive)

left_sz -- size of the left hand side of a bipartite graph:
Vertices with ids between 0 and left_sz-1 are on the left hand side, and
vertices with ids between left_sz and adj.size()-1 are on the right hand side
In case of online algorithms we use the convention that left hand side 
  consists of online nodes.
*/
class Graph {
public:
	Graph(int n);
	void addVertex();
	void addEdge(int i, int j); // Does not check for duplicate edges
	void setLeftSize(int leftSize);
	vector<int> ranking(const vector<int>& perm);
	vector<int> minDegree();
	vector<int> karp_sipser();
	vector<int> greedy();
	vector<int> secondPass(vector<int> & firstPass);
	vector<int> thirdPass(const vector<int> & firstPass, 
		const vector<int> &secPass);
	void sortOffline(const vector<int>& perm);  // sort adjacency lists of 
												// online nodes wrt perm
	void printDebug();
	vector<int> find_augmenting_path(const vector<int> &online, 
		const vector<int> &offline);
	void augment(vector<int> & online, vector<int> &offline, 
		const vector<int> &path);
	void maxMatching(vector<int> & online);
	void getFeldmanAdvice(vector<int> &red, vector<int> & blue);
	void getBahmaniAdvice(vector<int> & red, vector<int> & blue);
	vector<int> getFeldmanMatching(const vector<int> & types, 
		const vector<int> & red, const vector<int> &blue, bool greedy);
	Graph createInstanceGraph(const vector<int> & types);
	vector<vector<pair<double, int> > > estimateFractionalOPTIIDMC(int rep);
	vector<int> getManshadiMatching(const vector<int> & types, 
		const vector<vector<pair<double, int> > > &frac, bool greedy);
	void maxFlow(const vector<vector<int> > &adj, map<pair<int, int>, int> &cap,
		map<pair<int, int>, int> &flow, int s, int t);
	void decomposeByFeldman(const vector<vector<int> > &adj3, int left,
		vector<int> &blue, vector<int> &red);
	vector<vector<int> > getJailletAdvice();
	vector<int> getJailletMatching(const vector<int> &types, 
		vector<vector<int > > & advice, bool greedy);
	vector<int> randomRanking();
	map<pair<int, int>, double> solveBrubachLP();
	void doGhandiRounding(map<pair<int, int>, double> & frac);
	void doBrubachCycleBreaking(map<pair<int, int>, int> & rounded);
	map<pair<int, int>, double> doBrubach2ndTransform(map<pair<int, int>, int> &
		rounded);
	vector<vector<pair<double, int> > > getBrubachAdvice();
	vector<int> getBrubachMatching(const vector<int> & types,  
		vector<vector<pair<double, int> > > &advice, bool greedy);

	int getLeftSize() const;
	int getNumVertices() const;
	int getNumEdges() const;
	void write(ostream out);

	static int countMatchingSize(const vector<int> & matching);
	static vector<int> findMaximalPathOrCycle(const vector<vector<int> > a);
private:
	vector<vector<int> > adj; // adjacency lists representation of the graph
	
	int left_sz; // left hand side size of bipartite graph
};

